use derive_builder::Builder;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;

use super::{Class, ClassAttribute, ClassAttributeBuilder, ClassBuilder, ClassGetter};
use crate::database::DataSource;
use crate::datasource::{Storage, StorageType};
use crate::error::Error;
use crate::mapper::ValueMapper;
use crate::modeling::{
    system_meta_database, ClassAttributePersistence, ClassPersistence, ClassPersistenceBuilder,
    ClassPersistenceGetter, ClassRelation, ClassRelationGetter, Value, ValueType,
};

pub const DATASOURCE_CLASS_IDENTIFIER: &'static str = "g01_datasource";

pub const DATASOURCE_CLASS_NAME: &'static str = "datasource";

pub const DATASOURCE_TABLE_NAME: &'static str = "_g01_meta_datasources";

#[derive(Debug, Serialize, Deserialize, Default, Clone, Builder, PartialEq)]
#[builder(name = "DataSourceEntityBuilder")]
#[builder(pattern = "mutable")]
#[builder(setter(into, strip_option), default)]
#[builder(derive(Debug))]
#[builder(build_fn(error = "Error"))]
pub struct DataSourceEntity {
    /// id
    pub id: i64,
    /// identifier
    pub identifier: String,
    /// 名称
    pub name: String,
    /// 名称
    pub title: String,
    /// 图标
    pub icon: Option<String>,
    /// domain identifier
    pub domain_identifiers: String,
    /// 存储类型
    pub storage_type: StorageType,
    /// 存储选项
    pub storage_options: String,
    /// 选项
    pub options: Option<String>,
    /// 备注
    pub description: String,
    /// 创建时间
    pub created_at: i64,
    /// 更新时间
    pub updated_at: i64,
}

//
crate::impl_from_value!(DataSourceEntity);
crate::impl_class_persistence_getter!(DataSourceEntity, DATASOURCE_TABLE_NAME);
crate::impl_class_relations_getter!(DataSourceEntity, vec![]);

impl ClassGetter for DataSourceEntity {
    fn get_name() -> anyhow::Result<String> {
        Ok(String::from(DATASOURCE_CLASS_NAME))
    }
    fn get_identifier() -> anyhow::Result<String> {
        Ok(String::from(DATASOURCE_CLASS_IDENTIFIER))
    }
    fn get_class() -> anyhow::Result<Class> {
        let mut attribute_builder = ClassAttributeBuilder::default();
        attribute_builder.class_identifier(DATASOURCE_CLASS_IDENTIFIER);

        let mut commons = super::common_attributes_with_builder(&attribute_builder)?;
        let mut append = vec![
            attribute_builder
                .clone()
                .name("domain_identifiers")
                .title("领域")
                .data_type(ValueType::String)
                .build()?,
            attribute_builder
                .clone()
                .name("storage_type")
                .title("存储类型")
                .data_type(ValueType::String)
                .build()?,
            attribute_builder
                .clone()
                .name("storage_options")
                .title("存储选项")
                .data_type(ValueType::String)
                .build()?,
        ];
        append.append(&mut commons);
        append.sort_by(|a, b| a.position.cmp(&b.position));
        let clazz = ClassBuilder::default()
            .identifier(DATASOURCE_CLASS_IDENTIFIER)
            .name(DATASOURCE_CLASS_NAME)
            .data_is_type(true)
            .is_persistent(true)
            .primary_key(String::from("identifier"))
            .attributes(append)
            .build()?;
        Ok(clazz)
    }
}

impl DataSourceEntity {
    pub fn datasource(&self) -> anyhow::Result<DataSource> {
        let mut ds =
            Storage::new(&self.storage_type, &self.storage_options)?.get_connector_datasource()?;
        ds.id = self.id.try_into()?;
        Ok(ds)
    }
}
